//------------------------------------------------------------------------------
//
// ...
// filename: strRound.as
// author: 小兵( blog.csdn.net/aosnowasp )
// created: 2014-5-13
// copyright (c) 2013 小兵( aosnow@yeah.net )
//
//------------------------------------------------------------------------------

package starfire.utils.strings
{

	/**
	 * 求一个对应进制值字符串的舍入值，与四舍五入同理
	 * <ul>
	 * <li>二进制 - 0舍1入</li>
	 * <li>八进制 - 3舍4入</li>
	 * <li>十进制 - 4舍5入</li>
	 * <li>十六进制 - 7舍8入</li>
	 * </ul>
	 * @param value 源数据字符串，必须是小数表示类型的源数据<code>（10.0101[2], 7.24651[8], 1.259[10], FA.80E2A[16]）</code>
	 * @param precision 精确到小数点后多少位，默认保持 2 位小数位（对应进制位）
	 * @param radix 按指定的进制规则进行舍入操作（允许的值为2、8、10、16，分别代表二进制、八进制、十进制、十六进制）
	 */
	public function str_round( value:String, precision:uint = 2, radix:uint = 2 ):String
	{
		var hi:int = radix == 2 ? 0 : ( radix == 8 ? 1 : ( radix == 10 ? 2 : ( radix == 16 ? 3 : -1 )));

		// 非法的进制参数
		if( hi == -1 )
			return value;

		// 检测超出后的第一位是否需要向前进 1 个单位
		var s:Array = value.split( "." );
		var r:String;

		// 不正确的精度参数
		if( precision >= s[ 1 ].length )
			return value;

		var cur:uint = parseInt( String( s[ 1 ]).substr( precision, 1 ), radix );

		if( cur < HALF_UP_FLAG[ hi ])
		{
			// 舍弃后面的数据 
			r = s[ 0 ] + "." + String( s[ 1 ]).substr( 0, precision );
		}
		else
		{
			// 需要向前进 1
			var dInt:int = parseInt( s[ 0 ], radix );
			var dDec:uint = parseInt( String( s[ 1 ]).substr( 0, precision ), radix );
			var rd:String = ( dDec + 1 ).toString( radix );
			
			// 若小数部分转回成字符串后的长度小于源数据中的小数部分的长度，则代表省去了前置的0，需要加回来
			rd.length < precision && ( rd = repeat( "0", precision - rd.length ) + rd );

			if( rd.length > precision )
			{
				dInt += uint( rd.substr( 0, 1 ));
				rd = rd.substr( 1 );
			}

			r = dInt.toString( radix ) + "." + rd;
		}

		return r.toUpperCase();
	}
}

// 当处理超出的第一位时，看是否大于等于以下数字，若是则进1，否则舍弃
const HALF_UP_FLAG:Vector.<uint> = Vector.<uint>([ 1, 4, 5, 8 ]);

// 每种进制，当累加1时，需要向前进1的上限，当下面的列表中的值再加上时，当前位变成0，并继续向前进1
const RADIX_UP_FLAG:Vector.<uint> = Vector.<uint>([ 1, 8, 9, 0xF ]);
